package com.wrater.zero.common.generator;


import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.google.common.base.CaseFormat;
import lombok.Data;


import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.util.*;

import org.apache.commons.lang3.StringUtils;

import static com.baomidou.mybatisplus.core.toolkit.StringPool.SLASH;
import static com.baomidou.mybatisplus.core.toolkit.StringPool.UNDERSCORE;
import static com.baomidou.mybatisplus.core.toolkit.StringPool.DOT;


// 代码生成器
// 执行 main 方法控制台输入模块表名回车自动生成对应项目目录中
@Data
public class CodeGenerator {

    private static String url;
    private static String driverClassName;
    private static String username;
    private static String password;
    private static String modelName;
    private static String tableName;
    private static String author;
    private static String entityIgnorePrefix;
    private static String groupPath;
    private static String modelsPath;
    private static String superEntityColumns;

    // 读取配置文件
    static {
        SAXReader saxReader = new SAXReader();
        String path = CodeGenerator.class.getClassLoader().getResource("db/generatorConfig.xml").getPath();
        try {
            Document document = saxReader.read(new File(path));
            Element root = document.getRootElement();
            url = root.elementText("url");
            driverClassName = root.elementText("driverClassName");
            username = root.elementText("username").trim();
            password = root.elementText("password");
            modelName = root.elementText("modelName");
            tableName = root.elementText("tableName");
            author = root.elementText("author");
            entityIgnorePrefix = root.elementText("entityIgnorePrefix");
            groupPath = root.elementText("groupPath");
            modelsPath = root.elementText("modelsPath");
            superEntityColumns = root.elementText("superEntityColumns");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public static String ROOT_PATH = "/src/main/java" ;

    public static String ENTITY_PATH = "/entity/" ;
    public static String VO_PATH = "/vo/" ;
    public static String DAO_PATH = "/dao/" ;
    public static String SERVICE_PATH = "/service/" ;
    public static String CONTROLLER_PATH = "/controller/" ;

    private static String codeRootPath = ROOT_PATH +  groupPath + modelsPath + SLASH + modelName;
    private static String groupModelPackage = groupPath.replaceAll(SLASH,DOT).replaceFirst(DOT, "") + DOT + modelsPath.replaceAll(SLASH,"") + DOT + modelName;
    private static String xmlRootPath = "/src/main/resources/mapper/" + modelName;


    private static String controllerPath = codeRootPath + "/controller/";
    private static String servicePath = codeRootPath + "/service/";
    private static String mapperPath = codeRootPath + "/dao/";
    private static String entityPath = codeRootPath + "/entity/";
    private static String voPath = codeRootPath + "/vo/";
    private static String xmlPath = xmlRootPath + SLASH;

    public static DbType DB_TYPE = DbType.MYSQL;
    public static String SUPER_ENTITY_CLASS = "com.wrater.zero.common.base.entity.BaseEntity" ;



    private static GlobalConfig globalConfig() {
        return new GlobalConfig()
                // 打开文件
                .setOpen(false)
                // 文件覆盖
                .setFileOverride(true)
                // 开启activeRecord模式
                .setActiveRecord(true)
                // XML ResultMap: mapper.xml生成查询映射结果
                .setBaseResultMap(true)
                // XML ColumnList: mapper.xml生成查询结果列
                .setBaseColumnList(true)
                // swagger注解; 须添加swagger依赖
                .setSwagger2(true)
                // 作者
                .setAuthor(author)
                // 设置实体类名称
                .setEntityName("%s")
                //设置服务类名称
                .setServiceName("%sService")
                ;
    }

    private static DataSourceConfig dataSourceConfig() {
        return new DataSourceConfig()
                // 数据库类型
                .setDbType(DB_TYPE)
                // 连接驱动
                .setDriverName(driverClassName)
                // 地址
                .setUrl(url)
                // 用户名
                .setUsername(username)
                // 密码
                .setPassword(password);
    }

    private static StrategyConfig strategyConfig() {
        StrategyConfig strategyConfig = new StrategyConfig()
                // 表名生成策略：下划线连转驼峰
                .setNaming(NamingStrategy.underline_to_camel)
                // 表字段生成策略：下划线连转驼峰
                .setColumnNaming(NamingStrategy.underline_to_camel)
                // 需要生成的表
                .setInclude(tableName.split(","))
                // 去除表前缀
                .setTablePrefix(entityIgnorePrefix)
                // 生成controller
                .setRestControllerStyle(true)
                // controller映射地址：驼峰转连字符
                .setControllerMappingHyphenStyle(false)
                // 设置父类
                .setSuperEntityClass("com.wrater.zero.common.base.entity.BaseEntity")
                .setSuperControllerClass("com.wrater.zero.common.base.controller.BaseController")
                .setSuperMapperClass("com.wrater.zero.common.base.dao.BaseMapper")
                .setSuperServiceClass("com.wrater.zero.common.base.service.AbstractService")
                // 是否启用builder 模式
                .setChainModel(true)
                // 是否为lombok模型; 需要lombok依赖
                .setEntityLombokModel(true)
                // 生成实体类字段注解
                .setEntityTableFieldAnnotationEnable(true)
                // 乐观锁、逻辑删除、表填充
//                .setVersionFieldName("version")
                .setLogicDeleteFieldName("is_deleted")
                .setTableFillList(Arrays.asList(
                        new TableFill("gmt_modified", FieldFill.UPDATE),
                        new TableFill("gmt_create", FieldFill.INSERT)
                ))
                // 生成类的时候排除的字符串(因为这些字段已经在父类中，子类无需再生成)
                .setSuperEntityColumns(
                        superEntityColumns.split(",")
                );
        //配置父类
            strategyConfig.setSuperEntityClass(SUPER_ENTITY_CLASS);
        return strategyConfig;
    }

    private static InjectionConfig injectionConfig() {
        return injectionConfig();
    }

    private static InjectionConfig injectionConfig(boolean isCreateExt) {
        return new InjectionConfig() {
            @Override
            public void initMap() {
                // 注入配置
                Map<String, Object> map = new HashMap<>(16);
                //指定表格的名称
                map.put("customerTableName", true);
                //需要生成扩展的时候执行
//                if (isCreateExt) {
//                    //扩展的表名
//                    map.put("extPackagePre", PACKAGE_PARENT_EXT);
//                    //controller包路径
//                    map.put("controllerPackage", PACKAGE_CONTROLLER);
//                    //service包名
//                    map.put("service", PACKAGE_NAME_SERVICE);
//                    //实现类包名
//                    map.put("serviceImpl", PACKAGE_NAME_IMPL);
//                    //mapper包名
//                    map.put("mapper", PACKAGE_NAME_MAPPER);
//                    //实现后缀
//                    map.put("serviceImplNameFix", EXT_SERVICE_CLASSNAME_IMPL);
//                    //类名扩展后缀
//                    map.put("classNameExt", EXT_ClASS_NAME);
//                }
                for (String tableName : tableName.split(",")) {
                    //指定每个类的serialVersionUID
                    long serialVersionUID = UUID.nameUUIDFromBytes(tableName.getBytes()).getLeastSignificantBits();
                    map.put(tableName, Math.abs(serialVersionUID));
                    //计算controller的路径
                    StringBuilder sb = new StringBuilder();
                    if (StringUtils.contains(tableName, UNDERSCORE)) {
                        sb.append(SLASH + tableName.substring(0, tableName.indexOf(UNDERSCORE)));
                        String url = tableName.substring(tableName.indexOf(UNDERSCORE) + 1);
                        sb.append(SLASH + CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, url));
                        map.put(tableName + "path", sb.toString());
                        continue;
                    }
                    sb.append(SLASH + CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, url));
                    map.put(tableName + "path", sb.toString());
                }
                this.setMap(map);
            }
        }
                // 判断是否创建文件
                .setFileCreate((configBuilder, fileType, filePath) -> {
                    // 检查文件目录，不存在自动递归创建
                    File file = new File(filePath);
                    System.out.println("生成文件---------" + filePath);
                    boolean exist = file.exists();
                    if (!exist) {
                        file.getParentFile().mkdirs();
                    }
                    return true;
                })
                // 自定义输出文件
                .setFileOutConfigList(fileOutConfigList(isCreateExt));
    }

    /**
     * 自定义输出路径
     *
     * @param isCreateExt
     * @return
     */
    private static List<FileOutConfig> fileOutConfigList(boolean isCreateExt) {
        List<FileOutConfig> list = new ArrayList<>();
        // 当前项目路径
        String projectPath = System.getProperty("user.dir");

        // 实体类文件输出
        list.add(new FileOutConfig(ENTITY_TEMPLATE) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + entityPath + tableInfo.getEntityName() + StringPool.DOT_JAVA;
            }
        });
        // vo文件输出
        list.add(new FileOutConfig(VO_TEMPLATE) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + voPath + tableInfo.getEntityName() + "VO" + StringPool.DOT_JAVA;
            }
        });
        // mapper xml文件输出
        list.add(new FileOutConfig(XML_TEMPLATE) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + xmlPath + tableInfo.getMapperName() + StringPool.DOT_XML;
            }
        });
        // mapper文件输出
        boolean add = list.add(new FileOutConfig(MAPPER_TEMPLATE) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + mapperPath + tableInfo.getMapperName() + StringPool.DOT_JAVA;
            }
        });
        // service文件输出
        list.add(new FileOutConfig(SERVICE_TEMPLATE) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + servicePath + tableInfo.getServiceName() + StringPool.DOT_JAVA;
            }
        });
        // controller文件输出
        list.add(new FileOutConfig(CONTROLLER_TEMPLATE) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + controllerPath + tableInfo.getControllerName() + StringPool.DOT_JAVA;
            }
        });
        return list;
    }

    public static void main(String[] args) {
//        boolean isCreateExt = false;
        boolean isCreateExt = true;
        builder(isCreateExt);
    }

    /**
     * 执行自动代码生成程序
     *
     * @param isCreateExt
     */
    private static void builder(boolean isCreateExt) {
        new AutoGenerator().setGlobalConfig(globalConfig())
                .setDataSource(dataSourceConfig())
                .setStrategy(strategyConfig())
                .setCfg(injectionConfig(isCreateExt))
                .setPackageInfo(
                        new PackageConfig()
                                .setParent(groupModelPackage)
                                .setPathInfo(new HashMap() )

                )
                .execute()
        ;
    }

    /**
     * entity输出模板
     */
    public static String ENTITY_TEMPLATE = "templates/entity.java.vm" ;
    /**
     * vo输出模板
     */
    public static String VO_TEMPLATE = "templates/vo.java.vm" ;
    /**
     * mapper.xml输出模板
     */
    public static String XML_TEMPLATE = "templates/mapper.xml.vm" ;
    /**
     * mapper.java输出模板
     */
    public static String MAPPER_TEMPLATE = "templates/mapper.java.vm" ;
    /**
     * service输出模板
     */
    public static String SERVICE_TEMPLATE = "templates/service.java.vm" ;
    /**
     * controller输出模板
     */
    public static String CONTROLLER_TEMPLATE = "templates/controller.java.vm" ;
}